#pragma once

#include "zen_game_texture.h"
#include "zen_game_figure.h"
#include "zen_number.h"
#include "zen_wrap.h"

#include <vector>
#include <mutex>

namespace Zen
{
	namespace Game
	{
		/// DustEmitor base class
		class DustEmitor
		{
		public:
			struct Vertex
			{
				std::vector<Point2> positions;
				std::vector<Color4f> colors;
				std::vector<float> sizes{};

				void Resize(size_t count)
				{
					positions.resize(count);
					colors.resize(count);
					sizes.resize(count);
				}
			};
			virtual void Initialize(size_t count) = 0;
			virtual void Update(float interval) = 0;

			Vertex const& GetVertexData() const;
			float GetEmitorAge() const;

			virtual ~DustEmitor() = default;

		protected:
			float mEmitorAge{};
			Vertex mVertexes;
			friend class Dust;
		};

		struct DustConfig
		{
			Color4f start_color = { 0.5f, 0.5f, 0.2f, 1.0f };
			Color4f start_color_var = { 0.2f, 0.2f, 0.1f, 0.f };

			Color4f end_color = { 1.0f, 1.0f, 0.0f, 0.0f };
			Color4f end_color_var = { 0, 0, 0, 0 };
			float start_size = 5;
			float end_size = 30;
			float start_size_var = 5;
			float end_size_var = 5;
			float start_alpha = 1.f;
			float start_alpha_var = 0.f;
			float end_alpha = 0.f;
			float end_alpha_var = 0;
			float par_life = 1;
			float par_life_var = 0.5f;

			// keep null to use the default Functions
			std::function<float(float s, float e, float v)> color_lerp_func;
			std::function<float(float s, float e, float v)> alpha_lerp_func;
			std::function<float(float s, float e, float v)> size_lerp_func;
		};

		struct GravityDustConfig : public DustConfig
		{
			float emit_angle = (float)ZEN_F_PI2;
			float emit_angle_var = 0;
			float emit_speed = 100.f;
			float emit_speed_var = 20.f;

			float gravity_radians = (float)ZEN_F_PI2;
			float gravity_radians_var = 0.f;
			float gravity_acc = 10.f;
			float gravity_acc_var = 0;

			Zen::Point2 emit_pos = { 0, 0 };
			Zen::Point2 emit_pos_var = { 0, 5 };
		};

		class GravityDustEmitor : public DustEmitor
		{
		public:
			GravityDustEmitor(GravityDustConfig const& config);

		public:
			virtual void Initialize(size_t count) override;
			virtual void Update(float interval) override;

			void ResetParticle(size_t nth);
			void UpdateParticle(size_t nth);

		public:
			struct Particle
			{
				Color4f color0;
				Color4f color1;
				float size0 = 0;
				float size1 = 0;
				float alpha0 = 0;
				float alpha1 = 0;
				float birth = 0;
				float life = 0;
				Zen::Point2 emit_speed;
				Zen::Point2 gravity;
				Zen::Point2 emit_position;
			};

		private:
			GravityDustConfig mConfig;

			std::vector<Particle> mParticles;

			friend class Dust;
		};

		struct GalaxyDustConfig : public DustConfig
		{
			float start_radius = 0;
			float start_radius_var = 0;
			float end_radius = 400.f;
			float end_radius_var = 0;
			float emit_angle = 0;
			float emit_angle_var = (float)ZEN_F_PI;
			float emit_angle_speed = (float)ZEN_F_PI / 2;
			float emit_angle_speed_var = 0;
			float emit_acceler = (float)ZEN_F_PI / 8;
			float emit_acceler_var = (float)ZEN_F_PI / 20;

			// keep null to use the default Functions
			std::function<float(float s, float e, float v)> radius_lerp_func;
		};

		class GalaxyDustEmitor : public DustEmitor
		{
		public:
			GalaxyDustEmitor(GalaxyDustConfig const& config);

		public:
			virtual void Initialize(size_t count) override;
			virtual void Update(float interval) override;

		protected:
			void ResetParticle(size_t nth);
			void UpdateParticle(size_t nth, float interval);

			struct Particle
			{
				Color4f color0;
				Color4f color1;
				float size0 = 0;
				float size1 = 0;
				float alpha0 = 0;
				float alpha1 = 0;
				float age = 0;
				float life = 0;

				float start_radius = 0;
				float end_radius = 0;
				float emit_angle = 0;
				float emit_angle_speed = 0;
				float angle_acceler = 0;
			};

		protected:
			GalaxyDustConfig mConfig;

			std::vector<Particle> mParticles;

			friend class Dust;
		};

		/*!
	 @class Dust
	 @abstract This is the dust particle main class.
	 */
		class Dust : public FigurePointTexture
		{
		public:
			Dust();
			void SetEmitor(std::shared_ptr<DustEmitor> emitor);

			std::shared_ptr<DustEmitor> GetEmitor();

			void SetDustCount(size_t count);
			void SetEmitorLife(float life);
			//void SetPointScale(float scale);
			bool IsRunning();
			bool IsInitialized();

			void RestartEmit();
			void StopEmit();

			virtual void OnReady(std::shared_ptr<RenderStack> stack, float) override;
			virtual void OnDraw() override;

		protected:
			std::shared_ptr<DustEmitor> mEmitor;

			size_t mTotalCount = 64;
			float mEmitorLife = 10000.f;
			float mRunningLife = 0.f;
			bool mIsInitialized = false;
			bool mIsRunning = true;
		};
	} // namespace Game
} // namespace Zen
